const fs = require('fs');
const path = require('path');
const spawn = require('cross-spawn');
const gitScm = require('@devpack/qakit').gitScm;
const baseDir = resolve('');
const repoDir = gitScm.getRepo();

function resolve(dir) {
  return path.resolve(__dirname, '..', dir);
}

// 扫描子工程
function scanEntries(dir) {
  return new Promise((resolve, reject) => {
    fs.readdir(dir, (err, entries) => {
      if (err) {
        reject(err);
      } else {
        entries = entries.map((entry) => normalizeEntry(entry, dir));
        resolve(entries);
      }
    });
  });
}

// 标准化构建任务配置
function normalizeEntry(entry, context) {
  const absPath = path.join(context, entry);
  const packPath = path.join(absPath, 'xpack.json');
  const colPath = path.join(absPath, 'portal-column.json');
  const isColumn = fs.existsSync(colPath);
  const hasLatentTemplate = fs.existsSync(path.join(absPath, 'index.html'));
  const userConf = require(packPath);
  const defaults = {
    target: 'app',
    name: entry,
    library: `__seeyonv8_${entry}`,
    filename: 'index',
    entry: 'index.js',
    template: hasLatentTemplate ? 'index.html' : resolve('scripts/template.html'),
    title: '',
    dest: entry
  };
  const conf = {
    ...defaults,
    ...userConf
  };

  conf.template = path.resolve(absPath, conf.template);
  conf.entry = path.resolve(absPath, conf.entry);
  conf.assetsDir = conf.dest;
  conf.indexPath = conf.home || path.join(conf.dest, 'index.html');
  conf.dest = resolve('dist');

  return {
    context,
    name: entry,
    dir: absPath,
    pack: conf,
    packFile: packPath,
    columnFile: isColumn ? colPath : ''
  };
}

// 获取当前分支起点到本次间的变更文件列表
function getDiffs(reg) {
  if (process.env.ENV) return;
  const initialRev = gitScm.getInitialCommit((line) => reg.test(line));
  if (!initialRev) return [];
  const files = gitScm.getDiffFiles('ACMR', initialRev, baseDir);
  const staged = gitScm.getStagedDiffFiles('ACMR', baseDir);
  return staged.concat(files);
}

// 识别变更文件，计算增量构建的工程列表
function mapIncremental(files) {
  return (tasks) => {
    // 全量构建场景
    // 1. 没有检测到文件变更，但执行了构建程序
    // 2. 变更了非子工程文件(可能是功能代码或配置文件)
    // 3. 本地构建(CI环境构建会提供环境变量ENV=PROD)
    const isBuildAll =
      !files || !files.length || files.some((f) => /^((?!src\/entries\/).)+$/.test(f));
    if (isBuildAll) return tasks;

    // 计算变更的子工程列表
    const partials = tasks.filter((task) => {
      const taskDir = task.dir.replace(repoDir, '');
      return files.some((f) => f.indexOf(taskDir) > -1);
    });
    return partials.length ? partials : tasks;
  };
}

// 构建核心
function build({ dir, name, pack, packFile, columnFile }) {
  const { target, entry, dest } = pack;
  const isLib = target === 'lib';
  const args = [
    'build',
    '--target',
    target,
    '--name',
    isLib ? pack.library : name,
    '--pack-dir',
    dir,
    '--assets-dir',
    pack.assetsDir,
    '--pack-conf',
    packFile,
    entry
  ];
  if (target === 'lib') {
    args.push('--filename');
    args.push(pack.assetsDir + '/index');
    args.push('--formats');
    args.push('umd-min');
    if (columnFile) {
      args.push('--pack-column');
      args.push(columnFile);
    }
  } else {
    args.push('--template');
    args.push(pack.template);
    args.push('--title');
    args.push(pack.title);
    args.push('--index-path');
    args.push(pack.indexPath);
  }

  return new Promise((resolve) => {
    const sout = [`>>>>>>>>>> Packing ${name} <<<<<<<<<<\n`];
    const proc = spawn('vue-cli-service', args, { env: { ...process.env, FORCE_COLOR: true } });
    proc.stdout.on('data', (data) => sout.push(data));
    proc.stderr.on('data', (data) => sout.push(data));
    proc.on('close', (code) => {
      console.log(sout.join(''));
      resolve(code);
    });
  });
}

// 批量构建
function batchBuild(tasks) {
  const procs = tasks.map((task) => build(task));
  return Promise.all(procs);
}

// 程序主入口
function main() {
  const context = resolve('src/entries');
  const callback = (res) => {
    const failed = res.some((code) => code);
    const msg = failed ? 'CAP-H5-BUILD-FAILED' : 'CAP-H5-BUILD-SUCCESS';
    console.log(msg);
  };

  // 构建指定工程
  const apps = process.argv.slice(2).map((app) => normalizeEntry(app, context));
  if (apps.length) {
    return batchBuild(apps).then(callback);
  }

  // 增量/全量构建(当前版本所有变动的文件列表)
  // CI环境构建会提供环境变量ENV=PROD，非CI环境则全量构建
  const files = process.env.ENV !== 'PROD' ? null : getDiffs(/\(origin\/\w+-release/);
  scanEntries(context)
    .then((tasks) => {
      const partials = mapIncremental(files)(tasks);
      const isBuildAll = partials.length === tasks.length;
      console.log(`[构建模式]: ${isBuildAll ? '全量' : '增量'}`);
      return partials;
    })
    .then(batchBuild)
    .then(callback);
}

main();
